package org.convallaria.infrastruct.rg.controller;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.convallaria.infrastruct.rg.health.ServiceHealthChecker;
import org.convallaria.infrastruct.rg.loadbalancer.CustomLoadBalancer;
import org.convallaria.infrastruct.rg.service.ServiceDiscoveryManager;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 服务发现控制器
 * 提供服务发现相关的REST API
 * 
 * @author gjh
 * @since 2025-01-27
 */
@Slf4j
@RestController
@RequestMapping("/api/registry")
@RequiredArgsConstructor
public class ServiceDiscoveryController {
    
    private final ServiceDiscoveryManager serviceDiscoveryManager;
    private final ServiceHealthChecker serviceHealthChecker;
    private final CustomLoadBalancer customLoadBalancer;
    
    /**
     * 获取所有服务列表
     * 
     * @return 服务列表
     */
    @GetMapping("/services")
    public Map<String, Object> getServices() {
        List<String> services = serviceDiscoveryManager.getServices();
        
        Map<String, Object> result = new HashMap<>();
        result.put("services", services);
        result.put("count", services.size());
        result.put("timestamp", System.currentTimeMillis());
        
        return result;
    }
    
    /**
     * 获取指定服务的实例列表
     * 
     * @param serviceId 服务ID
     * @return 实例列表
     */
    @GetMapping("/services/{serviceId}/instances")
    public Map<String, Object> getServiceInstances(@PathVariable String serviceId) {
        List<ServiceInstance> instances = serviceDiscoveryManager.getInstances(serviceId);
        
        Map<String, Object> result = new HashMap<>();
        result.put("serviceId", serviceId);
        result.put("instances", instances);
        result.put("count", instances.size());
        result.put("timestamp", System.currentTimeMillis());
        
        return result;
    }
    
    /**
     * 获取指定服务的健康实例列表
     * 
     * @param serviceId 服务ID
     * @return 健康实例列表
     */
    @GetMapping("/services/{serviceId}/healthy-instances")
    public Map<String, Object> getHealthyInstances(@PathVariable String serviceId) {
        List<ServiceInstance> instances = serviceDiscoveryManager.getHealthyInstances(serviceId);
        
        Map<String, Object> result = new HashMap<>();
        result.put("serviceId", serviceId);
        result.put("instances", instances);
        result.put("count", instances.size());
        result.put("timestamp", System.currentTimeMillis());
        
        return result;
    }
    
    /**
     * 根据版本获取服务实例
     * 
     * @param serviceId 服务ID
     * @param version 版本号
     * @return 指定版本的实例列表
     */
    @GetMapping("/services/{serviceId}/instances/by-version")
    public Map<String, Object> getInstancesByVersion(
            @PathVariable String serviceId,
            @RequestParam String version) {
        List<ServiceInstance> instances = serviceDiscoveryManager.getInstancesByVersion(serviceId, version);
        
        Map<String, Object> result = new HashMap<>();
        result.put("serviceId", serviceId);
        result.put("version", version);
        result.put("instances", instances);
        result.put("count", instances.size());
        result.put("timestamp", System.currentTimeMillis());
        
        return result;
    }
    
    /**
     * 根据区域获取服务实例
     * 
     * @param serviceId 服务ID
     * @param region 区域
     * @return 指定区域的实例列表
     */
    @GetMapping("/services/{serviceId}/instances/by-region")
    public Map<String, Object> getInstancesByRegion(
            @PathVariable String serviceId,
            @RequestParam String region) {
        List<ServiceInstance> instances = serviceDiscoveryManager.getInstancesByRegion(serviceId, region);
        
        Map<String, Object> result = new HashMap<>();
        result.put("serviceId", serviceId);
        result.put("region", region);
        result.put("instances", instances);
        result.put("count", instances.size());
        result.put("timestamp", System.currentTimeMillis());
        
        return result;
    }
    
    /**
     * 检查服务是否可用
     * 
     * @param serviceId 服务ID
     * @return 服务可用性
     */
    @GetMapping("/services/{serviceId}/available")
    public Map<String, Object> isServiceAvailable(@PathVariable String serviceId) {
        boolean available = serviceDiscoveryManager.isServiceAvailable(serviceId);
        int totalCount = serviceDiscoveryManager.getInstanceCount(serviceId);
        int healthyCount = serviceDiscoveryManager.getHealthyInstanceCount(serviceId);
        
        Map<String, Object> result = new HashMap<>();
        result.put("serviceId", serviceId);
        result.put("available", available);
        result.put("totalInstances", totalCount);
        result.put("healthyInstances", healthyCount);
        result.put("timestamp", System.currentTimeMillis());
        
        return result;
    }
    
    /**
     * 获取服务实例详细信息
     * 
     * @param serviceId 服务ID
     * @param instanceId 实例ID
     * @return 实例详细信息
     */
    @GetMapping("/services/{serviceId}/instances/{instanceId}")
    public Map<String, Object> getInstance(
            @PathVariable String serviceId,
            @PathVariable String instanceId) {
        ServiceInstance instance = serviceDiscoveryManager.getInstance(serviceId, instanceId);
        
        Map<String, Object> result = new HashMap<>();
        result.put("serviceId", serviceId);
        result.put("instanceId", instanceId);
        result.put("instance", instance);
        result.put("found", instance != null);
        result.put("timestamp", System.currentTimeMillis());
        
        return result;
    }
    
    /**
     * 检查服务实例健康状态
     * 
     * @param serviceId 服务ID
     * @param instanceId 实例ID
     * @return 健康状态
     */
    @GetMapping("/services/{serviceId}/instances/{instanceId}/health")
    public Map<String, Object> checkInstanceHealth(
            @PathVariable String serviceId,
            @PathVariable String instanceId) {
        ServiceInstance instance = serviceDiscoveryManager.getInstance(serviceId, instanceId);
        
        Map<String, Object> result = new HashMap<>();
        result.put("serviceId", serviceId);
        result.put("instanceId", instanceId);
        result.put("found", instance != null);
        
        if (instance != null) {
            boolean healthy = serviceHealthChecker.checkInstanceHealth(instance);
            ServiceHealthChecker.ServiceInstanceInfo info = serviceHealthChecker.getInstanceInfo(instance);
            
            result.put("healthy", healthy);
            result.put("reachable", info.isReachable());
            result.put("checkTime", info.getCheckTime());
        } else {
            result.put("healthy", false);
            result.put("reachable", false);
        }
        
        result.put("timestamp", System.currentTimeMillis());
        
        return result;
    }
    
    /**
     * 获取负载均衡信息
     * 
     * @param serviceId 服务ID
     * @return 负载均衡信息
     */
    @GetMapping("/services/{serviceId}/loadbalancer")
    public Map<String, Object> getLoadBalancerInfo(@PathVariable String serviceId) {
        List<ServiceInstance> instances = serviceDiscoveryManager.getInstances(serviceId);
        List<ServiceInstance> healthyInstances = serviceDiscoveryManager.getHealthyInstances(serviceId);
        
        Map<String, Object> result = new HashMap<>();
        result.put("serviceId", serviceId);
        result.put("totalInstances", instances.size());
        result.put("healthyInstances", healthyInstances.size());
        result.put("available", !healthyInstances.isEmpty());
        
        if (!healthyInstances.isEmpty()) {
            // 演示不同的负载均衡策略
            ServiceInstance randomInstance = customLoadBalancer.randomChoose(healthyInstances);
            ServiceInstance weightedInstance = customLoadBalancer.weightedChoose(healthyInstances);
            
            result.put("randomInstance", randomInstance != null ? randomInstance.getUri().toString() : null);
            result.put("weightedInstance", weightedInstance != null ? weightedInstance.getUri().toString() : null);
        }
        
        result.put("timestamp", System.currentTimeMillis());
        
        return result;
    }
}
